package com.iris.live.services.report.handlers;

import com.iris.live.services.common.DateFormatUtils;
import com.iris.live.services.common.StringUtils;
import com.iris.live.services.data.models.ReportConfig;
import com.iris.live.services.report.data.ReportContext;
import com.iris.live.services.report.data.orgline.OrgUnit;
import com.iris.live.services.report.data.orgline.OrglineContext;
import com.iris.live.services.report.data.timeline.TimeUnit;
import com.iris.live.services.report.data.timeline.TimelineContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Description:
 * @author: Tony.Zhang
 * @Date: 2017-10-24 18:25
 **/
public class SaleManagementRowHandler extends BaseReportRowHandler{
    private static Logger logger = LoggerFactory.getLogger(SaleManagementRowHandler.class);

    @Override
    public boolean isSupport() {
        return true;
    }

    @Override
    public void handle(Map reportRow, ReportConfig config, ReportContext context, List<Map> resultSet4ReportRow, Map<String, Map>  all) throws Exception{
        if(context instanceof TimelineContext){
            handleTimLine(reportRow, config, context, resultSet4ReportRow, all);
        }else if(context instanceof OrglineContext){
            handleOrgLine(reportRow, config, context, resultSet4ReportRow, all);
        }
    }

    /**
     * 组织架构维度行数据处理
     * @param reportRow
     * @param config
     * @param context
     * @param resultSet4ReportRow
     * @throws Exception
     */
    private void handleOrgLine(Map reportRow, ReportConfig config, ReportContext context, List<Map> resultSet4ReportRow, Map<String, Map>  all) throws Exception{
        String fullPath = this.getFullPath(config);
        OrglineContext bContext = (OrglineContext) context;
        String code = config.getAinCode();

        if("品牌".equals(config.getStatType())){
            String unit = null;
            for(OrgUnit ou : bContext.getOrgUnits()){
                unit = ou.getValue();
                Map cell = (Map) reportRow.get(fullPath + "_" + ou.getText());
                if(code.startsWith("厂家零售完成率")){
                    cell.put(config.getCategory() + "Value", getOrgLineRatio(resultSet4ReportRow, ou, "实际零售NBI", "零售签署目标"));
                }else if(code.startsWith("ROS零售完成率")){
                    cell.put(config.getCategory() + "Value", getOrgLineRatio(resultSet4ReportRow, ou, "新车销量", "ROS零售目标"));
                }else if(code.startsWith("采购完成率")){
                    cell.put(config.getCategory() + "Value", getOrgLineRatio(resultSet4ReportRow, ou, "实际采购", "采购签署目标"));
                }else if(code.startsWith("精品销售毛利率")){
                    cell.put(config.getCategory() + "Value", getOrgLineRatio(resultSet4ReportRow, ou, "后市场产品销售毛利", "后市场产品营业额"));
                }else if(code.startsWith("延保渗透率")){
                    cell.put(config.getCategory() + "Value", getOrgLineRatio(resultSet4ReportRow, ou, "新车五星延保台数", "新车销量"));
                }else if(code.startsWith("新保渗透率")){
                    cell.put(config.getCategory() + "Value", getOrgLineRatio(resultSet4ReportRow, ou, "新保台数", "新车销量"));
                }else if(code.startsWith("金融渗透率")){
                    cell.put(config.getCategory() + "Value", getOrgLineRatio(resultSet4ReportRow, ou, "金融台数", "新车销量"));
                }else if(code.startsWith("GPI率")){
                    cell.put(config.getCategory() + "Value", getOrgLineRatio(resultSet4ReportRow, ou, "gpi_price", "新车外部销售收入"));
                }else if(code.startsWith("GPIII率")){
                    cell.put(config.getCategory() + "Value", getOrgLineRatio(resultSet4ReportRow, ou, "gpiii_price", "新车外部销售收入"));
                }else if(code.startsWith("销售T.GP率")){
                    cell.put(config.getCategory() + "Value", getOrgLineRatio(resultSet4ReportRow, ou, "tgp_amount", "vehicle_sale_gross_amount"));
                }else if(code.startsWith("精品产品单车营业额")){
                    cell.put(config.getCategory() + "Value", getOrgLineRatio(resultSet4ReportRow, ou, "后市场产品营业额", "新车销量"));
                }else if(code.startsWith("单车金融服务费收入")){
                    cell.put(config.getCategory() + "Value", getOrgLineRatio(resultSet4ReportRow, ou, "金融服务费", "金融台数"));
                }else if(code.startsWith("库存深度")){
                    cell.put(config.getCategory() + "Value", getOrgLineRatio(resultSet4ReportRow, ou, "期末库存台数", "三个月平均销量"));
                }
            }
        }

        if("累计".equals(config.getStatType())){
            String formular = config.getFormularExpression();
            if(StringUtils.isNotNullOrBlank(formular)) {
                if (formular.indexOf("/") > 0) {
                    String[] formulars = formular.replaceAll("groovy", "").replaceAll("[(]", "").replaceAll("[)]", "").split("/");
                    List<String> numeratorValues = StringUtils.tokenize(formulars[0], "()+");
                    List<String> denominatorValues = StringUtils.tokenize(formulars[1], "()+");
                    for (OrgUnit unit : bContext.getOrgUnits()) {
                        Double numerator = 0d, denominator = 0d;

                        Map cell = (Map) reportRow.get(fullPath + "_" + unit.getValue());

                        for (String value : numeratorValues) {
                            value = value.substring(0, value.lastIndexOf("_")) + "_" + unit.getValue();
                            numerator += getValue(all, value, config.getCategory());
                        }

                        for (String value : denominatorValues) {
                            value = value.substring(0, value.lastIndexOf("_")) + "_" + unit.getValue();
                            denominator += getValue(all, value, config.getCategory());

                            if (config.getAinCode().startsWith("库存深度")) {
                                all.remove(value);
                            }
                        }

                        cell.put(config.getCategory() + "Value", denominator > 0 ? numerator / denominator : 0);
                    }
                } else {
                    List<String> values = StringUtils.tokenize(config.getFormularExpression().replaceAll("groovy", "").replaceAll("[(]", "").replaceAll("[)]", ""), "()+");

                    for (OrgUnit unit : bContext.getOrgUnits()) {
                        Map cell = (Map) reportRow.get(fullPath + "_" + unit.getValue());
                        Double d = 0d;
                        for (String value : values) {
                            value = value.substring(0, value.lastIndexOf("_")) + "_" + unit.getValue();
                            d += getValue(all, value, config.getCategory());

                            if (config.getAinCode().startsWith("三月平均实际零售ROS")) {
                                all.remove(value);
                            }
                        }

                        cell.put(config.getCategory() + "Value", d);
                    }
                }
            }
        }
    }

    /**
     * 时间维度行数据处理
     * @param reportRow
     * @param config
     * @param context
     * @param resultSet4ReportRow
     * @throws Exception
     */
    private void handleTimLine(Map reportRow, ReportConfig config, ReportContext context, List<Map> resultSet4ReportRow, Map<String, Map>  all) throws Exception{
        String fullPath = this.getFullPath(config);
        TimelineContext bContext = (TimelineContext) context;
        String code = config.getAinCode();
        Map params = context.getParams();
        String maxMonth;
        if(params.get("selectYear").equals(DateFormatUtils.getFormatDateToString(new Date(), "yyyy"))){
            maxMonth = DateFormatUtils.getFormatDateToString(new Date(), "MM");
        }else{
            maxMonth = "12";
        }

        if("品牌".equals(config.getStatType())){
            String unit = null;
            for(TimeUnit tu : bContext.getTimeUnits()){
                if(! tu.getType().equals(TimeUnit.TimeType.MONTH)){
                    Map cell = (Map) reportRow.get(fullPath + "_" + tu.getValue());
                    if(code.startsWith("厂家零售完成率")){
                        cell.put(config.getCategory() + "Value", getTimelineRatio(resultSet4ReportRow, tu, "实际零售NBI", "零售签署目标"));
                    }else if(code.startsWith("ROS零售完成率")){
                        cell.put(config.getCategory() + "Value", getTimelineRatio(resultSet4ReportRow, tu, "新车销量", "ROS零售目标"));
                    }else if(code.startsWith("采购完成率")){
                        cell.put(config.getCategory() + "Value", getTimelineRatio(resultSet4ReportRow, tu, "实际采购", "采购签署目标"));
                    }else if(code.startsWith("精品销售毛利率")){
                        cell.put(config.getCategory() + "Value", getTimelineRatio(resultSet4ReportRow, tu, "后市场产品销售毛利", "后市场产品营业额"));
                    }else if(code.startsWith("延保渗透率")){
                        cell.put(config.getCategory() + "Value", getTimelineRatio(resultSet4ReportRow, tu, "新车五星延保台数", "新车销量"));
                    }else if(code.startsWith("新保渗透率")){
                        cell.put(config.getCategory() + "Value", getTimelineRatio(resultSet4ReportRow, tu, "新保台数", "新车销量"));
                    }else if(code.startsWith("金融渗透率")){
                        cell.put(config.getCategory() + "Value", getTimelineRatio(resultSet4ReportRow, tu, "金融台数", "新车销量"));
                    }else if(code.startsWith("GPI率")){
                        cell.put(config.getCategory() + "Value", getTimelineRatio(resultSet4ReportRow, tu, "gpi_price", "新车外部销售收入"));
                    }else if(code.startsWith("GPIII率")){
                        cell.put(config.getCategory() + "Value", getTimelineRatio(resultSet4ReportRow, tu, "gpii_price", "新车外部销售收入"));
                    }else if(code.startsWith("销售T.GP率")){
                        cell.put(config.getCategory() + "Value", getTimelineRatio(resultSet4ReportRow, tu, "tgp_amount", "vehicle_sale_gross_amount"));
                    }else if(code.startsWith("精品产品单车营业额")){
                        cell.put(config.getCategory() + "Value", getTimelineRatio(resultSet4ReportRow, tu, "后市场产品营业额", "新车销量"));
                    }else if(code.startsWith("单车金融服务费收入")){
                        cell.put(config.getCategory() + "Value", getTimelineRatio(resultSet4ReportRow, tu, "金融服务费", "金融台数"));
                    }
                }
            }
        }

        if("品牌".equals(config.getStatType()) && (code.startsWith("库存深度"))){
            for(TimeUnit tu : bContext.getTimeUnits()){
                Map cell = (Map) reportRow.get(fullPath + "_" + tu.getValue());

                cell.put(config.getCategory() + "Value", getStockDegree4Time(config, tu, context, all));
            }
        }

        if("品牌".equals(config.getStatType()) && (code.startsWith("期末库存台数") || code.startsWith("库龄60天以上台数")
                || code.startsWith("库龄60天以上比例") || code.startsWith("库龄大于120天库存台数") || code.startsWith("库龄60_119天库存台数")
                || code.startsWith("库龄60天以下库存台数") || code.startsWith("销售顾问人数"))
                ){
            for(TimeUnit tu : bContext.getTimeUnits()){
                Map cell = (Map) reportRow.get(fullPath + "_" + tu.getValue());

                if(tu.getType().equals(TimeUnit.TimeType.YEAR)){
                    cell.put(config.getCategory() + "Value", getValue(config, reportRow, maxMonth, "12"));
                }else if(tu.getType().equals(TimeUnit.TimeType.QUARTER) && tu.getValue().equals("Q1")){
                    cell.put(config.getCategory() + "Value", getValue(config, reportRow, maxMonth, "03"));
                }else if(tu.getType().equals(TimeUnit.TimeType.QUARTER) && tu.getValue().equals("Q2")){
                    cell.put(config.getCategory() + "Value", getValue(config, reportRow, maxMonth, "06"));
                }else if(tu.getType().equals(TimeUnit.TimeType.QUARTER) && tu.getValue().equals("Q3")){
                    cell.put(config.getCategory() + "Value", getValue(config, reportRow, maxMonth, "09"));
                }else if(tu.getType().equals(TimeUnit.TimeType.QUARTER) && tu.getValue().equals("Q4")){
                    cell.put(config.getCategory() + "Value", getValue(config, reportRow, maxMonth, "12"));
                }
            }
        }

        if("累计".equals(config.getStatType())){
            if(code.startsWith("库存深度")){
                for(TimeUnit tu : bContext.getTimeUnits()){
                    Map cell = (Map) reportRow.get(fullPath + "_" + tu.getValue());

                    cell.put(config.getCategory() + "Value", getStockDegree4Time(config, tu, context, all));
                }
            }else {
                String formular = config.getFormularExpression();
                if(StringUtils.isNotNullOrBlank(formular)) {
                    if (formular.indexOf("/") > 0) {
                        String[] formulars = formular.replaceAll("groovy", "").replaceAll("[(]", "").replaceAll("[)]", "").split("/");
                        List<String> numeratorValues = StringUtils.tokenize(formulars[0], "()+");
                        List<String> denominatorValues = StringUtils.tokenize(formulars[1], "()+");
                        for (TimeUnit tu : bContext.getTimeUnits()) {
                            Double numerator = 0d, denominator = 0d;
                            Map cell = (Map) reportRow.get(fullPath + "_" + tu.getValue());

                            numerator = 0d;
                            denominator = 0d;
                            for (String value : numeratorValues) {
                                value = value.substring(0, value.lastIndexOf("_")) + "_" + tu.getValue();
                                numerator += getValue(all, value, config.getCategory());
                            }

                            for (String value : denominatorValues) {
                                value = value.substring(0, value.lastIndexOf("_")) + "_" + tu.getValue();
                                denominator += getValue(all, value, config.getCategory());
                            }

                            cell.put(config.getCategory() + "Value", denominator > 0 ? numerator / denominator : 0);
                        }
                    } else {
                        List<String> values = StringUtils.tokenize(config.getFormularExpression().replaceAll("groovy", "").replaceAll("[(]", "").replaceAll("[)]", ""), "()+");
                        for (TimeUnit tu : bContext.getTimeUnits()) {
                            Double d = 0d;
                            Map cell = (Map) reportRow.get(fullPath + "_" + tu.getValue());
                            d = 0d;
                            for (String value : values) {
                                value = value.substring(0, value.lastIndexOf("_")) + "_" + tu.getValue();
                                d += getValue(all, value, config.getCategory());
                            }
                            cell.put(config.getCategory() + "Value", d);
                        }
                    }
                }
            }
        }
    }

    /**
     * 取库存深度
     * @param timeUnit
     * @param context
     * @param all
     * @return
     * @throws Exception
     */
    private Double getStockDegree4Time(ReportConfig config, TimeUnit timeUnit, ReportContext context, Map<String, Map>  all) throws Exception{
        Map params = context.getParams();
        String maxMonth = null;
        if(params.get("selectYear").equals(DateFormatUtils.getFormatDateToString(new Date(), "yyyy"))){
            maxMonth = DateFormatUtils.getFormatDateToString(new Date(), "MM");
        }else{
            maxMonth = "12";
        }

        TimeUnit tu = null;
        if(timeUnit.getType().equals(TimeUnit.TimeType.YEAR)){
            //如果当前年份，取最新月份的库存深度作为年库存深度，否则取12月份库存深度
            tu  = new TimeUnit(TimeUnit.TimeType.MONTH, maxMonth, 0);
            return getMonthlyStockDegree(config, tu, all);
        }else if(timeUnit.getType().equals(TimeUnit.TimeType.QUARTER)){
            //如果当前年，当前季度，，取最新月份的库存作为季度库存深度，否则取季度末库存深度
            if(timeUnit.getValue().equals("Q1")){
                if(Integer.valueOf(maxMonth) > 3){
                    maxMonth = "03";
                }
                tu  = new TimeUnit(TimeUnit.TimeType.MONTH, maxMonth, 0);
            }else if(timeUnit.getValue().equals("Q2")){
                if(Integer.valueOf(maxMonth) > 6){
                    maxMonth = "06";
                }else if(Integer.valueOf(maxMonth) < 4){
                    return 0d;
                }
                tu  = new TimeUnit(TimeUnit.TimeType.MONTH, maxMonth, 0);
            }else if(timeUnit.getValue().equals("Q3")){
                if(Integer.valueOf(maxMonth) > 9){
                    maxMonth = "09";
                }else if(Integer.valueOf(maxMonth) < 7){
                    return 0d;
                }

                tu  = new TimeUnit(TimeUnit.TimeType.MONTH, maxMonth, 0);
            }else{
                tu  = new TimeUnit(TimeUnit.TimeType.MONTH, maxMonth, 0);
            }

            return getMonthlyStockDegree(config, tu, all);
        }else{
            return getMonthlyStockDegree(config, timeUnit, all);
        }
    }

    /**
     * 取月库存深度，一月取一月库存/一月零售， 2）二月取二月库存/一月 + 二月零售平均数 ， 3) 其他月取当前月库存数/前三月零售平均
     * @param config
     * @param timeUnit
     * @param all
     * @return
     */
    private double getMonthlyStockDegree(ReportConfig config,  TimeUnit timeUnit, Map<String, Map>  all){
        String category = config.getCategory();

        String flag = config.getAinCode().substring(config.getAinCode().lastIndexOf("_") + 1);

        Integer averageSaleVolumn = 0;

        Integer  stockNum = Double.valueOf(all.get("期末库存台数_" + flag + "_" + timeUnit.getValue()).get(category + "Value").toString()).intValue();
        if(timeUnit.getValue().equals("01")){
            averageSaleVolumn = Double.valueOf(all.get("实际零售ROS_" + flag + "_01").get(category + "Value").toString()).intValue();
        }else if(timeUnit.getValue().equals("02")){
            averageSaleVolumn = (Double.valueOf(all.get("实际零售ROS_" + flag + "_01").get(category + "Value").toString()).intValue() +
                    Double.valueOf(all.get("实际零售ROS_" + flag + "_02").get(category + "Value").toString()).intValue()) / 2;
        }else{
            averageSaleVolumn = (Double.valueOf(all.get("实际零售ROS_" + flag + "_" + getTimeUnit(timeUnit, 2)).get(category + "Value").toString()).intValue() +
                    Double.valueOf(all.get("实际零售ROS_" + flag + "_" + getTimeUnit(timeUnit, 1)).get(category + "Value").toString()).intValue() +
                    Double.valueOf(all.get("实际零售ROS_" + flag + "_" + timeUnit.getValue()).get(category + "Value").toString()).intValue()) / 3;
        }

        return Double.valueOf(averageSaleVolumn > 0 ? new Double(stockNum)/new Double(averageSaleVolumn) : 0);
    }

    private String getTimeUnit(TimeUnit tu, int value){
        int i = Integer.parseInt(tu.getValue()) - value;

        return i < 10 ? "0"+i : String.valueOf(i);
    }

    private Double getValue(Map<String, Map>  all, String key, String category){
        if(all.containsKey(key)){
            return all.get(key) == null ? 0d : Double.valueOf(Double.valueOf(all.get(key).get(category + "Value").toString()));
        }

        return 0d;
    }

    private Double getValue(ReportConfig config, Map reportRow, String lastMonth, String selectedMonth){
        String fullPath = this.getFullPath(config);
        Map selectedCell = null;

        if(Integer.valueOf(lastMonth) > Integer.valueOf(selectedMonth)){
            selectedCell = (Map) reportRow.get(fullPath + "_" + selectedMonth);
        }else{
            selectedCell = (Map) reportRow.get(fullPath + "_" + lastMonth);
        }

        return Double.valueOf(selectedCell.get(config.getCategory() + "Value").toString());
    }

    /**
     *
     * @param resultSet4ReportRow
     * @param timeUnit
     * @param numeratorColumn
     * @param denominatorColumn
     * @return
     */
    private Double getTimelineRatio(List<Map> resultSet4ReportRow, TimeUnit timeUnit,  String numeratorColumn, String denominatorColumn){
        int startMonth = 0, endMonth = 0;

        if(timeUnit.getType().equals(TimeUnit.TimeType.YEAR)){
            startMonth = 1;
            endMonth = 12;
        }else if(timeUnit.getType().equals(TimeUnit.TimeType.QUARTER)){
            if(timeUnit.getValue().equalsIgnoreCase("Q1")){
                startMonth = 1;
                endMonth = 3;
            }else if(timeUnit.getValue().equalsIgnoreCase("Q2")){
                startMonth = 4;
                endMonth = 6;
            }else if(timeUnit.getValue().equalsIgnoreCase("Q3")){
                startMonth = 7;
                endMonth = 9;
            }else if(timeUnit.getValue().equalsIgnoreCase("Q4")){
                startMonth = 10;
                endMonth = 12;
            }
        }

        int month;
        Double numerator = 0d, denominator = 0d;
        for(Map data : resultSet4ReportRow){
            month = Integer.valueOf(data.get("date").toString());

            if(month >= startMonth && month <= endMonth ){
                numerator += Double.valueOf(data.get(numeratorColumn).toString());
                denominator += Double.valueOf(data.get(denominatorColumn).toString());
            }
        }

        if(Math.abs(denominator) > 0){
            return numerator/denominator;
        }else{
            return 0d;
        }
    }

    /**
     *
     * @param resultSet4ReportRow
     * @param unit
     * @param numeratorColumn
     * @param denominatorColumn
     * @return
     */
    private Double getOrgLineRatio(List<Map> resultSet4ReportRow, OrgUnit unit,  String numeratorColumn, String denominatorColumn){
        Double numerator = 0d, denominator = 0d;
        for(Map data : resultSet4ReportRow){
            if(data.get(unit.getOrgColumn()).equals(unit.getValue())){
                if(StringUtils.isNotNullOrBlank(data.get(numeratorColumn))) {
                    numerator += Double.valueOf(data.get(numeratorColumn).toString());
                }

                if(StringUtils.isNotNullOrBlank(data.get(denominatorColumn))) {
                    denominator += Double.valueOf(data.get(denominatorColumn).toString());
                }
            }
        }

        if(Math.abs(denominator) > 0){
            return numerator/denominator;
        }else{
            return 0d;
        }
    }
}
